package cate.game.attr;

import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.*;

@SuppressWarnings("unchecked")
@NoteClass("属性")
public class Attr<T> implements Serializable {

    @NoteField("原始数据Map<属性枚举(Integer), 属性值(Double)>")
    public Map<Integer, Double> raw = new HashMap<>();

    @JsonIgnore
    public boolean isEmpty(){
        return raw.isEmpty();
    }

    public void parse(String code) {
        if (StringUtils.isBlank(code)) {
            return;
        }
        String[] kvs = code.split("#");
        for (String kv : kvs) {
            if (StringUtils.isBlank(kv)) {
                continue;
            }
            String[] kvArr = kv.split(":");
            if (kvArr.length >= 2) {
                int k = Integer.parseInt(kvArr[0]);
                double v = Double.parseDouble(kvArr[1]);
                Double old = raw.get(k);
                if (old != null) {
                    raw.put(k, v + old);
                } else {
                    raw.put(k, v);
                }
            }
        }
    }

    public Double getValue(int type) {
        return raw.get(type);
    }

    public Double getValueDefault(int type, Double defaultValue) {
        Double v = getValue(type);
        return v != null ? v : defaultValue;
    }

    public void setValue(int type, Double v) {
        if (v == null) {
            return;
        }
        raw.put(type, v);
    }

    /** 深拷贝一份数据 */
    public Attr copy() {
        Attr cp = new Attr();
        copy(cp);
        return cp;
    }

    /** 深拷贝数据 */
    public void copy(Attr cp) {
        this.raw.forEach(
                (k, v) -> {
                    cp.raw.put(k, v);
                });
    }

    /** 属性改变 */
    public T add(int attrType, double valueChange) {
        Double old = raw.get(attrType);
        if (old == null) {
            raw.put(attrType, valueChange);
        } else {
            raw.put(attrType, old + valueChange);
        }
        return (T) this;
    }

    /** 属性相加 */
    public T add(Attr attr) {
        return calc(attr, true);
    }

    /** 属性相减 */
    public T subtract(Attr attr) {
        return calc(attr, false);
    }

    /** 拉伸 */
    public T scale(double times) {
        raw.keySet()
                .forEach(
                        k -> {
                            Double v = raw.get(k);
                            if (v != null) {
                                v = v * times;
                                raw.put(k, v);
                            }
                        });
        return (T) this;
    }

    public void scale(int attr, double times) {
        Double v = raw.get(attr);
        if (v != null) {
            v = v * times;
            raw.put(attr, v);
        }
    }

    protected int[] getKeyEnum() {
        Set<Integer> set = new HashSet<>(this.raw.keySet());
        int[] keys = new int[set.size()];
        Iterator<Integer> iterator = set.iterator();
        int i = 0;
        while (iterator.hasNext()) {
            keys[i] = iterator.next();
            i++;
        }
        return keys;
    }

    private T calc(Attr attr, boolean add) {
        if (attr == null || attr.isEmpty()) {
            return (T) this;
        }
        for (int k : attr.getKeyEnum()) {
            Double thisV = raw.get(k);
            Double tarV = attr.getValue(k);
            if (thisV == null && tarV == null) {
                continue;
            }
            if (thisV == null) {
                thisV = 0.0;
            }
            if (tarV == null) {
                tarV = 0.0;
            }
            if (add) {
                setValue(k, thisV + tarV);
            } else {
                setValue(k, thisV - tarV);
            }
        }
        return (T) this;
    }

    protected String getKeyName(Integer k) {
        return k.toString();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("【");
        raw.forEach(
                (k, v) -> {
                    sb.append(getKeyName(k));
                    sb.append(":");
                    sb.append(String.format("%1.0f", v));
                    sb.append(", ");
                });
        if (!raw.isEmpty()) {
            sb.delete(sb.length() - 1, sb.length());
        }
        sb.append("】");
        return sb.toString();
    }
}
